package com.yxb.cms.architect.interceptor;

import com.alibaba.fastjson.JSONArray;
import com.yxb.cms.architect.constant.BussinessCode;
import com.yxb.cms.architect.utils.BussinessMsgUtil;
import com.yxb.cms.architect.utils.DateUtil;
import com.yxb.cms.architect.utils.OpenApiUtil;
import com.yxb.cms.domain.vo.DbAuthManager;
import com.yxb.cms.service.AuthManagerService;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 添加拦截控制器
 * @author rengp
 */

@Component
@Log4j2
public class SignInterceptor implements HandlerInterceptor {


    @Autowired
    private AuthManagerService authManagerService;

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {

        //appkey
        String appKey = httpServletRequest.getParameter("appKey");
        //timeStamp
        String timeStamp = httpServletRequest.getParameter("timeStamp");
        //para
        String paras = httpServletRequest.getParameter("paras");

        //sign
        String sign  = httpServletRequest.getParameter("sign");
        //判断appKey,timeStamp,para 参数是否为空
        if(StringUtils.isNotEmpty(appKey) && StringUtils.isNotEmpty(timeStamp) && StringUtils.isNotEmpty(paras) && StringUtils.isNotEmpty(sign)){


            //验证时间戳,防止重放攻击，时间戳相差超过1分钟，认定为非法操作
            if((DateUtil.getSecond()-DateUtil.toSecond(Long.valueOf(timeStamp)))>60){
                log.error("调用接口异常,签名超时：{}",Math.abs(DateUtil.getSecond()-DateUtil.toSecond(Long.valueOf(timeStamp))));
                String error = JSONArray.toJSONString(BussinessMsgUtil.returnCodeMessage(BussinessCode.GLOBAL_SIGN_ERROR));
                writeErrorData(httpServletResponse,error);
                return false;
            }

            //验证appKey是否已授权
            DbAuthManager authManager =  authManagerService.selectAuthManager(appKey);
            if(authManager == null){
                log.error("调用接口异常,appKey未授权：{}",appKey);
                String error = JSONArray.toJSONString(BussinessMsgUtil.returnCodeMessage(BussinessCode.GLOBAL_SIGN_ERROR));
                writeErrorData(httpServletResponse,error);
                return false;
            }

            //验证sign 签名,可以考虑将url一起加入签名验证
            String localsign = OpenApiUtil.genSign(appKey,timeStamp,paras,authManager.getAuthSecret());
            if(!StringUtils.equals(localsign,sign)){
                log.error("调用接口异常,签名验证失败sign：{},localsign:{}",sign,localsign);
                String error = JSONArray.toJSONString(BussinessMsgUtil.returnCodeMessage(BussinessCode.GLOBAL_SIGN_ERROR));
                writeErrorData(httpServletResponse,error);
                return false;
            }

            return true;
        }else{
            //参数不能为空
            log.error("调用接口异常,参数不能为空,appKey:{},timeStamp:{},paras:{}",appKey,timeStamp,paras);
            String error = JSONArray.toJSONString(BussinessMsgUtil.returnCodeMessage(BussinessCode.GLOBAL_PARAMS_NULL));
            writeErrorData(httpServletResponse,error);
            return false;
        }
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
    }
    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

    }

    /**
     * 输出异常信息
     */
    private void writeErrorData(HttpServletResponse httpServletResponse,String error) throws IOException {
        httpServletResponse.setCharacterEncoding("UTF-8");
        httpServletResponse.getWriter().write(error);
        httpServletResponse.flushBuffer();
    }
}
